package cn.iocoder.yudao.module.infra.controller.app.zip;

import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.infra.api.zip.ZipDownloadApi;
import cn.iocoder.yudao.module.infra.api.zip.dto.ZipDownloadReqDTO;
import cn.iocoder.yudao.module.infra.api.zip.dto.ZipDownloadRespDTO;
import cn.iocoder.yudao.module.infra.service.zip.ZipDownloadService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import java.io.File;
import java.io.FileInputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;

import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;

/**
 * ZIP下载控制器
 *
 * @author 芋道源码
 */
@Tag(name = "管理后台 - ZIP下载")
@RestController
@RequestMapping("/infra/zip")
@Validated
@Slf4j
public class AppZipDownloadController implements ZipDownloadApi {

    @Resource
    private ZipDownloadService zipDownloadService;

    @PostMapping("/download")
    @Operation(summary = "下载文件并打包成ZIP")
    @Override
    public CommonResult<ZipDownloadRespDTO> downloadZip(@Valid @RequestBody ZipDownloadReqDTO reqDTO) {
        ZipDownloadRespDTO result = zipDownloadService.downloadZip(reqDTO);
        return success(result);
    }

    @Override
    public void downloadZipStream(ZipDownloadReqDTO reqDTO, OutputStream outputStream) {
        zipDownloadService.downloadZipStream(reqDTO, outputStream);
    }

    @PostMapping("/download/stream")
    @Operation(summary = "下载文件并直接返回ZIP流")
    public void downloadZipStream(@Valid @RequestBody ZipDownloadReqDTO reqDTO, HttpServletResponse response) {
        try {
            // 设置响应头
            response.setContentType("application/zip");
            response.setHeader("Content-Disposition",
                    "attachment; filename=\"" + URLEncoder.encode(reqDTO.getZipFileName(), StandardCharsets.UTF_8.name()) + "\"");

            try ( OutputStream os = response.getOutputStream()) {
                this.downloadZipStream(reqDTO, os);
            }
        } catch (Exception e) {
            log.error("[downloadZipStream][流式下载ZIP异常]", e);
            throw new ServiceException(500, "流式下载ZIP失败: " + e.getMessage());
        }
    }

    @PostMapping("/download/async")
    @Operation(summary = "异步下载文件并打包成ZIP")
    @Override
    public CommonResult<String> downloadZipAsync(@Valid @RequestBody ZipDownloadReqDTO reqDTO) {
        String taskId = zipDownloadService.downloadZipAsync(reqDTO);
        return success(taskId);
    }

    @GetMapping("/task/{taskId}")
    @Operation(summary = "查询异步下载任务状态")
    @Parameter(name = "taskId", description = "任务ID", required = true)
    @Override
    public CommonResult<ZipDownloadRespDTO> getAsyncTaskStatus(@PathVariable("taskId") String taskId) {
        ZipDownloadRespDTO result = zipDownloadService.getAsyncTaskStatus(taskId);
        return success(result);
    }

    @GetMapping("/download/{taskId}")
    @Operation(summary = "下载ZIP文件", description = "根据任务ID下载生成的ZIP文件")
    public void downloadZipFile(@PathVariable("taskId") String taskId, HttpServletResponse response) {
        ZipDownloadRespDTO result = zipDownloadService.getAsyncTaskStatus(taskId);

        if (result == null) {
            throw new RuntimeException("任务不存在: " + taskId);
        }

        if (result.getZipFilePath() == null) {
            throw new RuntimeException("ZIP文件尚未生成完成");
        }

        try {
            File zipFile = new File(result.getZipFilePath());
            if (!zipFile.exists()) {
                throw new RuntimeException("ZIP文件不存在或已被清理");
            }

            // 设置响应头
            response.setContentType("application/zip");
            response.setHeader("Content-Disposition",
                "attachment; filename=\"" + URLEncoder.encode(result.getZipFileName(), "UTF-8") + "\"");
            response.setContentLengthLong(zipFile.length());

            // 读取文件并写入响应流
            try (FileInputStream fis = new FileInputStream(zipFile);
                 OutputStream os = response.getOutputStream()) {
                byte[] buffer = new byte[8192];
                int bytesRead;
                while ((bytesRead = fis.read(buffer)) != -1) {
                    os.write(buffer, 0, bytesRead);
                }
                os.flush();
            }

            // 下载完成后清理文件
            zipDownloadService.cleanupTempFiles(zipFile, null);

        } catch (Exception e) {
            log.error("[downloadZipFile][下载ZIP文件失败] taskId: {}", taskId, e);
            throw new RuntimeException("下载ZIP文件失败: " + e.getMessage());
        }
    }

}
